package com.example.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 用户服务切面类 - 这就是"切面（Aspect）"
 * 
 * @Aspect 注解标识这是一个切面，它封装了横切关注点的逻辑
 * 横切关注点包括：日志记录、性能监控、安全检查、事务管理等
 */
@Aspect
@Component
public class UserServiceAspect {

    /**
     * 定义切点（Pointcut） - 指定在哪些连接点应用通知
     * 
     * 这个切点表达式的含义：
     * - execution: 方法执行时的连接点
     * - public: 公共方法
     * - * com.example.service.UserService.*: UserService类的所有方法
     * - (..): 任意参数
     */
    @Pointcut("execution(public * com.example.service.UserService.*(..))")
    public void userServiceMethods() {
        // 这个方法体为空，它只是作为切点的载体
        // 实际的切点定义在@Pointcut注解中
    }

    /**
     * 前置通知（Before Advice） - 在目标方法执行之前执行
     * 用于：参数验证、日志记录、权限检查等
     */
    @Before("userServiceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("\n🚀 [前置通知] 方法即将执行: " + joinPoint.getSignature().getName());
        System.out.println("📝 [前置通知] 方法参数: " + java.util.Arrays.toString(joinPoint.getArgs()));
        System.out.println("🏠 [前置通知] 目标对象: " + joinPoint.getTarget().getClass().getSimpleName());
    }

    /**
     * 后置通知（After Returning Advice） - 在目标方法正常执行完成后执行
     * 用于：结果处理、缓存更新、通知发送等
     */
    @AfterReturning(pointcut = "userServiceMethods()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("✅ [后置通知] 方法执行成功: " + joinPoint.getSignature().getName());
        System.out.println("📤 [后置通知] 返回结果: " + result);
    }

    /**
     * 异常通知（After Throwing Advice） - 在目标方法抛出异常时执行
     * 用于：异常处理、错误日志、回滚操作等
     */
    @AfterThrowing(pointcut = "userServiceMethods()", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        System.out.println("❌ [异常通知] 方法执行异常: " + joinPoint.getSignature().getName());
        System.out.println("🔥 [异常通知] 异常信息: " + ex.getMessage());
    }

    /**
     * 最终通知（After Advice） - 无论目标方法是否正常执行都会执行
     * 用于：资源清理、日志记录、统计信息等
     */
    @After("userServiceMethods()")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("🔚 [最终通知] 方法执行完毕: " + joinPoint.getSignature().getName());
        System.out.println("───────────────────────────────────────");
    }

    /**
     * 环绕通知（Around Advice） - 最强大的通知类型
     * 可以在目标方法执行前后都执行代码，甚至可以决定是否执行目标方法
     * 用于：性能监控、事务管理、安全检查等
     * 
     * 这里单独为 createUser 方法定义环绕通知进行性能监控
     */
    @Around("execution(* com.example.service.UserService.createUser(..))")
    public Object monitorPerformance(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("\n⏱️  [环绕通知-前] 开始性能监控...");
        long startTime = System.currentTimeMillis();
        
        try {
            // 执行目标方法 - 这是关键步骤！
            Object result = proceedingJoinPoint.proceed();
            
            long endTime = System.currentTimeMillis();
            System.out.println("📊 [环绕通知-后] 方法执行耗时: " + (endTime - startTime) + "ms");
            System.out.println("🎯 [环绕通知-后] 性能监控完成");
            
            return result;
        } catch (Throwable throwable) {
            long endTime = System.currentTimeMillis();
            System.out.println("⚠️ [环绕通知-异常] 方法执行耗时: " + (endTime - startTime) + "ms");
            System.out.println("💥 [环绕通知-异常] 捕获到异常: " + throwable.getMessage());
            throw throwable; // 重新抛出异常
        }
    }

    /**
     * 专门针对删除操作的切点和通知 - 演示更精确的切点定义
     */
    @Pointcut("execution(* com.example.service.UserService.deleteUser(Long)) && args(userId)")
    public void deleteUserWithId(Long userId) {
        // 切点：删除用户方法，且参数为Long类型的userId
    }

    /**
     * 针对删除操作的前置通知 - 演示参数注入
     */
    @Before("deleteUserWithId(userId)")
    public void beforeDeleteUser(Long userId) {
        System.out.println("\n🗑️  [删除前置通知] 即将删除用户ID: " + userId);
        System.out.println("🔍 [删除前置通知] 正在进行删除前安全检查...");
        
        // 这里可以添加删除前的安全检查逻辑
        if (userId == 1L) {
            System.out.println("⚠️ [删除前置通知] 警告：正在删除管理员用户！");
        }
    }
} 